#include "thread_pool.h"
#include <stdio.h>
// stat函数
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
// opendir函数
#include <sys/types.h>
#include <dirent.h>
// 全局错误码声明所在的头文件
#include <errno.h>  
// strerror函数       
#include <string.h> 
#include <dirent.h>

// 线程池全局变量
thread_pool *pool;

// 文件路径结构体
struct file
{
    char old_file[1024];
    char new_file[1024];
};

// 复制文件函数
void* cpfile(void* arg)
{
    struct file *p = (struct file *)arg;

    // 1、打开源文件
    FILE* fp =  fopen(p->old_file, "r+");
    if(fp == NULL)
    {
        printf("PROBLEM: open %s error; REASON: %s; LINE: %d;\n",p->old_file, strerror(errno), __LINE__);
        exit(0);
    }

    // 2、创建新文件
    FILE* xfp =  fopen(p->new_file, "w+");
    if(xfp == NULL)
    {
        printf("PROBLEM: open %s error; REASON: %s; LINE: %d;\n",p->new_file, strerror(errno), __LINE__);
        exit(1);
    }

    // 3、将源文件的内容赋值到新文件中
    while (1)
    {
        // 读取源文件内容
        int ch = fgetc(fp);
        if (feof(fp))   // 没有到达末尾返回0             ->假
        {               // 返回非零值代表已经到达文件末尾 ->真
           break;
        }

        // 将输入写入到新文件中
        fputc(ch, xfp);
        
    }
    printf("%s 文件拷贝成功\n", p->old_file);

    // 4、关闭文件
    fclose(fp);
    fclose(xfp);

    // 释放堆空间
    free(p);
}


// 复制目录函数
void cpdir(char const *old_dir, char const* new_dir)
{
    // 1、打开存在目录
    DIR* dp = opendir(old_dir);
    if(dp == NULL)
    {
        printf("PROBLEM: opendir %s error; REASON: %s; LINE: %d;\n", old_dir, strerror(errno), __LINE__);
        exit(0);
    }

    // 2、创建新的目录
    mkdir(new_dir, 0777);

    // 3、读取目录
    while (1)
    {
        // a、读取目录的内容
        struct dirent *p = readdir(dp);
        if(p == NULL)
        {
            break;
        }
    
        // b、跳过所有.开头的隐藏文件
        if(p->d_name[0] == '.')
        {
            continue;
        }

        // c、判断是否为目录文件(d)
        if(p->d_type == DT_DIR)
        {
            // 继续检索
            char old_path[4096] = {0};
            char new_path[4096] = {0};

            sprintf(old_path, "%s/%s", old_dir, p->d_name);  // 拼接上一级目录
            sprintf(new_path, "%s/%s", new_dir, p->d_name); 
            cpdir(old_path, new_path);                       // 递归调用

        }

        // d、判断是否为普通文件(-)
        if(p->d_type == DT_REG)
        {
            // 初始化文件结构体
            struct file  *f = malloc(sizeof(struct file));

            // 获取文件的路径
            sprintf(f->old_file, "%s/%s", old_dir, p->d_name);
            sprintf(f->new_file, "%s/%s", new_dir, p->d_name);
            printf("正在拷贝 %s\n", f->new_file);

            // 添加拷贝任务
            THREAD_POOL_AddTask(pool, cpfile, (void*)f);

        }
    }
    closedir(dp);
}



// 主函数
int main(int argc, char const *argv[])
{
    if (argc != 3)
    {
        printf("请输入源目录和新目录\n");
        return -1;
    }
    
    // 1、初始化线程池(公司创建完毕，一开始有5个员工)
    pool = malloc(sizeof(thread_pool));
    THREAD_POOL_Init(pool, 5);

    // 2、执行拷贝目录的操作
    cpdir(argv[1], argv[2]);

    // 3、销毁线程池
    THREAD_POOL_Destroy(pool);
    
    return 0;
}
